/*
 * controlRobot14.cpp
 *
 *  Created on: Nov 7, 2013
 *      Author: m
 */

#include "DefinicionesComunes.h"
#include "CPrinter.h"
#include <ctime>
#include "ICinta13A.h"
#include "IRobot11A.h"
#include "ICinta13B.h"
#include "IRobot11B.h"
#include "IRobot14.h"
#include "ControladorR14Consumidor.h"
#include "ControladorR14Productor.h"
#include "DSMManager.h"

using ipc::CPrinter;

typedef enum{ CINTA_A, CINTA_B } cintaEntrada_t;

int main ( int argc, char* argv[] )
{
    DSMManager::inicializar("robot14");

    ControladorR14Consumidor controlador;
    ControladorR14Productor  controlador2;

    ICinta13A *cinta13A;
    ICinta13B *cinta13B;
    IRobot11A *robot11A;
    IRobot11B *robot11B;
    IRobot14  *robot14Cons;

    ICinta15 *cinta15;
    IRobot14 *robot14Prod;
    IRobot16 *robot16;

    cinta13A = &controlador;
    cinta13B = &controlador;
    robot11A = &controlador;
    robot11B = &controlador;
    robot14Cons = &controlador;

    cinta15 = &controlador2;
    robot14Prod = &controlador2;
    robot16 = &controlador2;

    cintaEntrada_t cintaSeleccionada;

    bool tieneElemsA;
    bool tieneElemsB;

    int nElemsA;
    int nElemsB;

    int sleepTime;

    bool depositoOk;

    ElementoProduccion elemento;

    srand( getpid() );

    CPrinter::setHeader("R14");

    while ( true )
    {
        CPrinter::printOut( "Verifico si la cinta13A tiene elementos" );
        tieneElemsA = cinta13A->tieneElementos();


        CPrinter::printOut( "Verifico si la cinta13B tiene elementos" );
        tieneElemsB = cinta13B->tieneElementos();


        if ( !tieneElemsA && !tieneElemsB )
        {
            CPrinter::printOut( "Esperando Elementos en las cintas 13" );

            robot14Cons->esperarNuevoElemento();
        }

        /*
         * Selecciono la cinta con la mayor cantidad de elementos, si ambas
         *  tienen la misma cantidad selecciono una al azar
         */
        nElemsA = cinta13A->contarElementos();
        nElemsB = cinta13B->contarElementos();

        CPrinter::printOut( "Cantidad de elementos: A:%d - B:%d",
               nElemsA, nElemsB );

        if ( nElemsA > nElemsB )
        {
            cintaSeleccionada = CINTA_A;
        }
        else
        {
            if ( nElemsA < nElemsB )
            {
                cintaSeleccionada = CINTA_B;
            }
            else
            {
                if ( random() % 2 == 0 )
                {
                    cintaSeleccionada = CINTA_A;
                }
                else
                {
                    cintaSeleccionada = CINTA_B;
                }
            }
        }

        if ( cintaSeleccionada == CINTA_A )
        {
            CPrinter::printOut( "Seleccionada Cinta 13A" );

            /*
             * Si el elemento no está en el extremo de este robot, avanzo la cinta
             *  para poder retirarlo, asimismo al avanzar la cinta notifico que
             *  hay espacio vacio al inicio para que el productor se despierte si
             *  es que estaba esperando lugar.
             */
            while ( cinta13A->avanzar() )
            {
                sleepTime = SLEEP_AVANZAR_CINTA;
                CPrinter::printOut( "Avanzando la cinta 13A durante: %ds",
                        sleepTime );
                sleep( sleepTime );

                if ( robot11A->esperaEspacioVacio() )
                {
                    CPrinter::printOut( "Despertando al Robot 11A");

                    robot11A->notificarEspacioVacio();
                }
            }

            /*
             * Finalmente quito el elemento de la cinta, si la primer posicion esta
             *  ocupada avanzo la cinta una vez y finalmente notifico al productor
             *  que hay un nuevo espacio libre en la cinta
             */
            elemento = cinta13A->quitar();

            sleepTime = SLEEP_QUITAR_ELEMENTO;
            CPrinter::printOut( "Quitando elemento de cinta 13A durante: %ds",
                    sleepTime );
            sleep( sleepTime );

            CPrinter::printOut( "Obtenido el elemento: %d de la cinta 13A",
                    elemento.productoId );

            if ( robot11A->esperaEspacioVacio() )
            {
                cinta13A->avanzar();


                sleepTime = SLEEP_AVANZAR_CINTA;
                CPrinter::printOut( "Avanzando la cinta 13A durante: %ds",
                        sleepTime );
                sleep( sleepTime );

                CPrinter::printOut( "Despertando al Robot 11A");

            }

            robot11A->notificarQuiteElemento();
        }
        else
        {
            CPrinter::printOut( "Seleccionada Cinta 13B" );

            /*
             * Si el elemento no está en el extremo de este robot, avanzo la cinta
             *  para poder retirarlo, asimismo al avanzar la cinta notifico que
             *  hay espacio vacio al inicio para que el productor se despierte si
             *  es que estaba esperando lugar.
             */
            while ( cinta13B->avanzar() )
            {
                sleepTime = SLEEP_AVANZAR_CINTA;
                CPrinter::printOut( "Avanzando la cinta 13B durante: %ds",
                        sleepTime );
                sleep( sleepTime );

                if ( robot11B->esperaEspacioVacio() )
                {
                    CPrinter::printOut( "Despertando al Robot 11B");

                    robot11B->notificarEspacioVacio();
                }
            }

            /*
             * Finalmente quito el elemento de la cinta, si la primer posicion esta
             *  ocupada avanzo la cinta una vez y finalmente notifico al productor
             *  que hay un nuevo espacio libre en la cinta
             */
            elemento = cinta13B->quitar();

            sleepTime = SLEEP_QUITAR_ELEMENTO;
            CPrinter::printOut( "Quitando elemento de cinta 13B durante: %ds",
                    sleepTime );
            sleep( sleepTime );

            CPrinter::printOut( "Obtenido el elemento: %d de la cinta 13B",
                    elemento.productoId );

            if ( robot11B->esperaEspacioVacio() )
            {
                cinta13B->avanzar();


                sleepTime = SLEEP_AVANZAR_CINTA;
                CPrinter::printOut( "Avanzando la cinta 13B durante: %ds",
                        sleepTime );
                sleep( sleepTime );

                CPrinter::printOut( "Despertando al Robot 11B");
            }

            robot11B->notificarQuiteElemento();
        }

        // A partir de acá empieza a depositar en la cinta 15
        depositoOk = cinta15->depositar( elemento );

        if ( !depositoOk )
        {
            CPrinter::printOut( "No se pudo depositar, esperando espacio vacio" );
            robot14Prod->esperarEspacioVacio();

            cinta15->depositar( elemento );
        }

        sleepTime = SLEEP_DEPOSITAR_ELEMENTO;
        CPrinter::printOut( "Depositando Elemento: %d en la cinta 15,"
                " durante: %ds", elemento.productoId, sleepTime );
        sleep( sleepTime );

        if ( cinta15->avanzar() )
        {
            sleepTime = SLEEP_AVANZAR_CINTA;
            CPrinter::printOut( "Avanzando la cinta 15 durante: %ds",
                    sleepTime );
            sleep( sleepTime );
        }

        robot16->notificarNuevoElemento();

    }

    return 0;
}
